#include <string.h>
#include <stdio.h>
#include "nano_db.h"

/*
 * Testcase1:
 *
 *  sub-tree at /config:config/equipment:equipment/equipment:radio:
 *
        <equipment:radio >
          <equipment:instance>1</equipment:instance>
          <equipment:modem-rsl-port>1</equipment:modem-rsl-port>
          <equipment:radio-daisy-chain-position>1</equipment:radio-daisy-chain-position>
          <equipment:rx-port>
            <equipment:instance>1</equipment:instance>
            <equipment:antenna-to-cif-delay>0.0</equipment:antenna-to-cif-delay>
            <equipment:cif-to-radio-gain>0.0</equipment:cif-to-radio-gain>
          </equipment:rx-port>
          <equipment:rx-port>
            <equipment:instance>2</equipment:instance>
            <equipment:antenna-to-cif-delay>0.0</equipment:antenna-to-cif-delay>
            <equipment:cif-to-radio-gain>0.0</equipment:cif-to-radio-gain>
          </equipment:rx-port>
          <!---.......>
        </equipment:radio> 
 */

void testcase1(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase1\n");
    printf("++++++++++++++++++++++++++++\n");

    int n;
    struct ndb_cursor_t cursor;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, equipment__ns, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, equipment__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/equipment:equipment/equipment:radio/equipment:rx-port";
    n = ndb_query(ndb, &ctx, xpath, &set);

    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }

    printf("query result: %u node returned\n", n);
   
    memset(&cursor, 0, sizeof(struct ndb_cursor_t));

    for_each_table(&set, &cursor) {

        printf("%s, id=%s: \n", ndbc_get_name(&cursor), ndbc_get_prop(&cursor, "id"));

        ndbc_down(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %f\n", ndbc_get_name(&cursor), ndbc_get_value_as_float(&cursor));

        ndbc_move(&cursor);
        printf("\t%s, = %f\n", ndbc_get_name(&cursor), ndbc_get_value_as_float(&cursor));

    }

    ndb_destory_context(&ctx);
}

/*
 * Testcase2:
 *  Path: /config:config/interface:interfaces/interface:ethernet:
 *
    <interface:interfaces xmlns:interface="http://skynetworks.com.cn/lte/bts/interfaces/2.0.0">
        <interface:ethernet name="eth0">
            <interface:instance>bh3</interface:instance>
            <interface:speed>auto</interface:speed>
            <interface:duplex>auto</interface:duplex>
            <interface:label></interface:label>
            <interface:max-frame-size>1522</interface:max-frame-size>
            <interface:requested-admin-state>unlock</interface:requested-admin-state>
            <interface:lumon>disable</interface:lumon>
            <interface:lumon-in-threshold-percent>90</interface:lumon-in-threshold-percent>
            <interface:lumon-out-threshold-percent>90</interface:lumon-out-threshold-percent>
            <interface:lumon-in-threshold-sec>0</interface:lumon-in-threshold-sec>
            <interface:lumon-out-threshold-sec>0</interface:lumon-out-threshold-sec>
            <interface:sub-if>
                <interface:instance>1</interface:instance>
                <interface:mtu>1500</interface:mtu>
                <interface:dhcpv4-client>disabled</interface:dhcpv4-client>
                <interface:dhcpv4-hostname>auto</interface:dhcpv4-hostname>
                <interface:dot1q-vlan-id>none</interface:dot1q-vlan-id>
                <interface:label></interface:label>
                <interface:app-type>1</interface:app-type>
                <interface:requested-admin-state>unlock</interface:requested-admin-state>
                <interface:ipv4>
                    <interface:address>10.1.178.102</interface:address>
                    <interface:mask>255.255.255.0</interface:mask>
                </interface:ipv4>
            </interface:sub-if>
        </interface:ethernet>
        <interface:ethernet name="eth1">
          <interface:instance>craft</interface:instance>
          <interface:speed>auto</interface:speed>
          <interface:duplex>auto</interface:duplex>
          <interface:label></interface:label>
          <interface:max-frame-size>1522</interface:max-frame-size>
          <interface:requested-admin-state>unlock</interface:requested-admin-state>
          <interface:lumon>disable</interface:lumon>
          <interface:lumon-in-threshold-percent>90</interface:lumon-in-threshold-percent>
          <interface:lumon-out-threshold-percent>90</interface:lumon-out-threshold-percent>
          <interface:lumon-in-threshold-sec>0</interface:lumon-in-threshold-sec>
          <interface:lumon-out-threshold-sec>0</interface:lumon-out-threshold-sec>
          <interface:sub-if>
            <interface:instance>1</interface:instance>
            <interface:mtu>1500</interface:mtu>
            <interface:dhcpv4-client>disable</interface:dhcpv4-client>
            <interface:dhcpv4-hostname>none</interface:dhcpv4-hostname>
            <interface:dot1q-vlan-id>none</interface:dot1q-vlan-id>
            <interface:label>craft-manual</interface:label>
            <interface:app-type>oam</interface:app-type>
            <interface:requested-admin-state>unlock</interface:requested-admin-state>
            <interface:ipv4>
              <interface:address>172.24.1.1</interface:address>
              <interface:mask>255.248.0.0</interface:mask>
            </interface:ipv4>
          </interface:sub-if>
        </interface:ethernet>
    </interface:interfaces>
 *
 */
void testcase2(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase2\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_cursor_t cursor;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, NULL, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/interface:interfaces/interface:ethernet";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }    

    memset(&cursor, 0, sizeof(struct ndb_cursor_t));

    for_each_table(&set, &cursor) {
        printf("ethernet %s {\n", ndbc_get_prop(&cursor, "name"));
        
        ndbc_down(&cursor);

        //'speed' node
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        //'duplex' node
        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

        ndbc_move(&cursor);
        printf("\t%s [%s] {\n", ndbc_get_name(&cursor), ndbc_path(&cursor));

        ndbc_down(&cursor);
        printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t%s {\n", ndbc_get_name(&cursor));

         ndbc_down(&cursor);
         printf("\t\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));

         ndbc_move(&cursor);
         printf("\t\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));
         printf("\t\t}\n");
         printf("\t}\n");

         /*ndbc_up(&cursor);
         ndbc_up(&cursor);*/

         printf("}\n");
    }

    ndb_destory_context(&ctx);
}

void testcase3(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase3\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_cursor_t cursor;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, NULL, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);


    const char* xpath = "/config:config/interface:interfaces/interface:ethernet";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }    

    memset(&cursor, 0, sizeof(struct ndb_cursor_t));

    for_each_table(&set, &cursor) {

        if (strcmp(ndbc_get_name(&cursor), "ethernet") == 0) {
            printf("ethernet %s {\n", ndbc_get_prop(&cursor, "name"));
            ndbc_down(&cursor);
        } else {
            continue;
        }
        
        /*
         * parse children node of 'ethernet' Node
         */
        while (ndbc_move(&cursor) == 0) {

            if (strcmp(ndbc_get_name(&cursor), "instance") == 0) {
                printf("\tinstance = %s\n", ndbc_get_value_as_str(&cursor));
            }

            if (strcmp(ndbc_get_name(&cursor), "speed") == 0) {
                printf("\tspeed = %s\n", ndbc_get_value_as_str(&cursor));
            }

            if (strcmp(ndbc_get_name(&cursor), "duplex") == 0) {
                printf("\tduplex = %s\n", ndbc_get_value_as_str(&cursor));
            }   
          
            if (strcmp(ndbc_get_name(&cursor), "max-frame-size") == 0) {
                printf("\tmax-frame-size = %s\n", ndbc_get_value_as_str(&cursor));
            }

            if (strcmp(ndbc_get_name(&cursor), "lumon") == 0) {
                printf("\tlumon = %s\n", ndbc_get_value_as_str(&cursor));
            }

            if (strcmp(ndbc_get_name(&cursor), "sub-if") == 0) {
                printf("\tsub-if {\n");
                ndbc_down(&cursor);
            
                /*
                * parse children node of 'sub-if' Node
                */
                do {
                    if (strcmp(ndbc_get_name(&cursor), "mtu") == 0) {
                        printf("\t\tmtu = %s\n", ndbc_get_value_as_str(&cursor));
                    }

                    if (strcmp(ndbc_get_name(&cursor), "dhcpv4-client") == 0) {
                        printf("\t\tdhcpv4-client = %s\n", ndbc_get_value_as_str(&cursor));
                    }

                    if (strcmp(ndbc_get_name(&cursor), "label") == 0) {
                        printf("\t\tlabel = %s\n", ndbc_get_value_as_str(&cursor));
                    }

                    if (strcmp(ndbc_get_name(&cursor), "dhcpv4-hostname") == 0) {
                        printf("\t\tdhcpv4-hostname = %s\n", ndbc_get_value_as_str(&cursor));
                    }

                    if (strcmp(ndbc_get_name(&cursor), "dot1q-vlan-id") == 0) {
                        printf("\t\tdot1q-vlan-id = %s\n", ndbc_get_value_as_str(&cursor));
                    }

                    if (strcmp(ndbc_get_name(&cursor), "app-type") == 0) {
                        printf("\t\tapp-type = %s\n", ndbc_get_value_as_str(&cursor));
                    }   

                    if (strcmp(ndbc_get_name(&cursor), "ipv4") == 0) {
                        printf("\t\tipv4 {\n");
                        ndbc_down(&cursor);
                        printf("\t\t\t%s = %s\n", ndbc_get_name(&cursor), ndbc_get_value_as_str(&cursor));
                        ndbc_move(&cursor);
                        printf("\t\t\tmask = %s\n", ndbc_get_value_as_str(&cursor));
                        printf("\t\t}\n");
                    }                    
                }  while (ndbc_move(&cursor) == 0);

                printf("\t}\n");
                ndbc_up(&cursor);
            }
            
        }

        printf("}\n");
    }

    ndb_destory_context(&ctx);
}

void testcase4(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase4\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, NULL, &ctx);
    
    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/interface:interfaces/interface:ethernet/interface:sub-if/interface:ipv4/interface:address";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }

    ndb_elem_ptr elem = ndb_get_first(&set);
    printf("node: %s, name: %s, value: %s\n", ndb_path(&set), ndb_get_name(elem), ndb_get_value_as_str(elem));

    ndb_destory_context(&ctx);
}

void testcase5(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase5\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, interface__ns, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/interface:interfaces/interface:ethernet";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }

    ndb_elem_ptr elem = ndb_get_first(&set);
    ndb_elem_ptr slibing = ndb_add_child(elem, NULL, "MACAddress", "00:11:22:33:44:55");
    ndb_elem_ptr slibing2 = ndb_add_sibling(slibing, NULL, "linkaddress", "aa:bb:cc:dd:ee:ff");
    ndb_set_prop(slibing, "ifname", "eth5");
    ndb_set_prop(slibing2, "ifname", "eth4");
    ndb_save_as(ndb, "new_config.xml");
    printf("    testcase5: config data save as new_config.xml\n");

    ndb_destory_context(&ctx);
}

void testcase6(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase6\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, interface__ns, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/interface:interfaces/interface:ethernet";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }

    int i;
    ndb_elem_ptr rootp, elp, elp1;
    struct ndb_value_t value;
    ndb_elset_ptr elset = get_elem_set(&set);

    for_each_subtree(elset, rootp, i) {
        for_each_children(rootp, elp) { /* children of node "ethernet" */

            /* set value */
            NDB_SET_U32(&value, 15400);
            ndb_compare_and_set(elp, "max-frame-size", &value);

            /* set value */
            NDB_SET_STR(&value, "lock-kevinx");
            ndb_compare_and_set(elp, "requested-admin-state", &value);

            /* get value */
            value.type = C_UINT32;
            if (ndb_compare_and_get(elp, "lumon-in-threshold-percent", &value) == 0)
                printf("lumon-in-threshold-percent = %u\n", NDB_GET_U32(&value));
            
            if (ndb_compare_and_get(elp, "lumon", NDB_TYPE(&value, C_STR)) == 0)
                printf("lumon-in-threshold-percent = %u\n", NDB_GET_U32(&value));
            
        
            if (ndb_compare(elp, "sub-if") == 0) { 

                for_each_children(elp, elp1) { /* sub-if of node "ethernet" */
                    NDB_SET_STR(&value, "kevinx");
                    ndb_compare_and_set(elp1, "dhcpv4-hostname", &value);
                }
            }
        }
    }

    ndb_save_as(ndb, "new_config1.xml");
    printf("    testcase5: config data save as new_config1.xml\n");
    ndb_destory_context(&ctx);
}

void testcase7(struct ndb_t* ndb)
{
    printf("\n\n============================\n");
    printf("           TestCase6\n");
    printf("++++++++++++++++++++++++++++\n");    

    int n;
    struct ndb_ctx_t ctx;
    struct ndb_tabset_t set;

    ndb_create_context(ndb, interface__ns, &ctx);

    struct ndb_ns_t* nslist[] = {skynetworks__ns, interface__ns};
    ndb_register_namespaces(&ctx, nslist, 2);

    const char* xpath = "/config:config/interface:interfaces/interface:ethernet";
    n = ndb_query(ndb, &ctx, xpath, &set);
    if (n == -1) {
        printf("no element found in path %s\n", xpath);
        return;
    }

    int i;
    ndb_elem_ptr rootp, elp, elp1;
    struct ndb_value_t value;
    ndb_elset_ptr elset = get_elem_set(&set);

    for_each_subtree(elset, rootp, i) {

        /* here only operate on ethernet i/f name is eth0 */
        if (ndb_has_prop_and_value(rootp, "name", "eth0") == 0) {
            for_each_children(rootp, elp) { /* children of node "ethernet" */

                /* set value */
                NDB_SET_U32(&value, 3330000);
                ndb_compare_and_set(elp, "max-frame-size", &value);
            
                /* get value */
                if (ndb_compare_and_get(elp, "lumon", NDB_TYPE(&value, C_STR)) == 0)
                    printf("lumon-in-threshold-percent = %u\n", NDB_GET_U32(&value));
            
        
                if (ndb_compare(elp, "sub-if") == 0) { 

                    for_each_children(elp, elp1) { /* sub-if of node "ethernet" */
                        NDB_SET_STR(&value, "joe");
                        ndb_compare_and_set(elp1, "dhcpv4-hostname", &value);
                    }
                }
            }
        }

        /* here only operate on ethernet i/f name is eth1 */
        /*if (ndb_has_prop(rootp, "ifname", "eth1") == 0) {
        }*/
    }

    ndb_save_as(ndb, "new_config1.xml");
    printf("    testcase5: config data save as new_config1.xml\n");
    ndb_destory_context(&ctx);
}

int main()
{

    struct ndb_t ndb;
    ndb_create(&ndb, "example_config.xml");

    testcase1(&ndb);
    testcase2(&ndb);
    testcase3(&ndb);
    testcase4(&ndb);
    testcase5(&ndb);
    testcase6(&ndb);
    testcase7(&ndb);

    ndb_destory(&ndb);

    return 0;
}
